package com.liming.order.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.liming.aftersales.client.AfterSalesClient;
import com.liming.auth.client.UserAuthClient;
import com.liming.cart.client.CartClient;
import com.liming.common.constant.LockConstants;
import com.liming.common.enums.*;
import com.liming.common.exception.BusinessException;
import com.liming.common.pojo.dto.authinfo.UserActivityAddDTO;
import com.liming.common.pojo.dto.order.OrderItemDTO;
import com.liming.common.pojo.dto.order.admin.OrderPageQuery;
import com.liming.common.pojo.dto.order.user.UserOrderDTO;
import com.liming.common.pojo.dto.order.user.mini.MiniOrderQueryPage;
import com.liming.common.pojo.dto.payment.PaymentUpdateDTO;
import com.liming.common.pojo.dto.payment.PrepayDTO;
import com.liming.common.pojo.entity.BaseEntity;
import com.liming.common.pojo.entity.order.Order;
import com.liming.common.pojo.entity.order.OrderItem;
import com.liming.common.pojo.vo.PageVO;
import com.liming.common.pojo.vo.dashboard.feign.FeignUserConsumeRankVO;
import com.liming.common.pojo.vo.order.OrderVO;
import com.liming.common.pojo.vo.order.mini.MiniOrderItemVO;
import com.liming.common.pojo.vo.order.mini.MiniOrderVO;
import com.liming.common.pojo.vo.order.openfeign.FeignOrderDetailVO;
import com.liming.common.pojo.vo.order.openfeign.FeignOrderItemVO;
import com.liming.common.pojo.vo.product.openfeign.FeignProductVO;
import com.liming.common.util.BeanUtils;
import com.liming.common.util.OrderUtils;
import com.liming.common.util.PageUtils;
import com.liming.common.util.ThreadLocalUtils;
import com.liming.common.util.mybatisplus.MPUtil;
import com.liming.coupon.client.CouponUserClient;
import com.liming.order.mapper.OrderMapper;
import com.liming.order.service.OrderItemMircoService;
import com.liming.order.service.OrderMircoService;
import com.liming.payment.client.PaymentClient;
import com.liming.product.client.ProductClient;
import com.liming.service.redisson.RLocker;
import com.liming.service.wx.WxClient;
import com.liming.service.wx.pojo.vo.PrepayVO;
import com.liming.stock.client.StockClient;
import com.wechat.pay.java.service.payments.model.Transaction;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.liming.common.constant.SystemConstants.ID;

/**
 * @author liming
 * @date 2025/2/5
 */
@Slf4j
@Service
@AllArgsConstructor
public class OrderMircoServiceImpl extends ServiceImpl<OrderMapper, Order>
        implements OrderMircoService, MPUtil<Order> {

    private final ProductClient productClient;
    private final OrderItemMircoService orderItemMircoService;
    private final AfterSalesClient afterSalesClient;
    private final UserAuthClient userAuthClient;
    private final CartClient cartClient;
    private final StockClient stockClient;
    private final CouponUserClient couponUserClient;
    private final WxClient wxClient;
    private final PaymentClient paymentClient;
    private final RLocker locker;

    @Override
    @GlobalTransactional
    public PrepayVO createOrder(UserOrderDTO userOrderDTO) {
        String strUserId = ThreadLocalUtils.get(ID);
        String lockKey = LockConstants.LOCK_ORDER + strUserId;
        PrepayVO vo = null;
        try {
            // tryLock的三个参数分别为 1. 获取锁可以等待的时间 2. 锁自动过期的时间 3. 时间单位
            if (locker.tryLock(lockKey, 0, 1, TimeUnit.MILLISECONDS)) {
                // 获取订单号
                String orderNo = OrderUtils.orderNo();
                List<OrderItemDTO> orderItemList = userOrderDTO.getOrderItemList();
                // 查询库存数量
                Map<Long, Integer> productIdAndAvailable = stockClient.allProductAvailableQuantityMap();
                // 下单订单中的 Map<商品ID, 数量>
                Map<Long, Integer> productIdAndQuantityMap =
                        orderItemList.stream().collect(Collectors.toMap(OrderItemDTO::getProductId, OrderItemDTO::getQuantity));
                for (Map.Entry<Long, Integer> entry : productIdAndQuantityMap.entrySet()) {
                    Integer stockQuantity = productIdAndAvailable.getOrDefault(entry.getKey(), 0);
                    Assert.isTrue(stockQuantity >= entry.getValue(), "商品" + entry.getKey() + "库存不足");
                }
                // 插入订单
                Order order = new Order();
                org.springframework.beans.BeanUtils.copyProperties(userOrderDTO, order);
                order.setOrderNo(orderNo);
                long userId = Long.parseLong(strUserId);
                order.setUserId(userId);
                // nickname
                Map<Long, String> idAndNickname = userAuthClient.userIdsAndNickname();
                String nickname = idAndNickname.get(userId);
                order.setUsername(nickname);
                save(order);
                Long orderId = order.getId();
                // 插入订单商品
                List<OrderItem> saveOrderItems = BeanUtils.toBean(orderItemList, OrderItem.class);
                for (OrderItem item : saveOrderItems) {
                    item.setOrderId(orderId);
                }
                orderItemMircoService.saveBatch(saveOrderItems);
                // 清除携带的商品用户购物车
                if (ObjectUtil.equal(userOrderDTO.getCart(), true)) {
                    // 去除购物车商品
                    cartClient.removeItemsByProductIds(productIdAndQuantityMap.keySet().stream().toList());
                }
                // 优惠券使用
                if (ObjectUtil.isNotNull(userOrderDTO.getCouponId())) {
                    couponUserClient.userOrderUseCoupon(userOrderDTO.getCouponId());
                }
                // 锁定库存
                stockClient.lockStockByProductIdAndQuantity(orderId, productIdAndQuantityMap);
                // wx 预支付
                String openid = userAuthClient.loginOpenid();
                vo = wxClient.wxJsapiPay(openid, orderNo);
                vo.setOrderId(orderId);
                vo.setOrderNo(orderNo);
                String prepayPackage = vo.getPrepayPackage();
                // 支付服务保存记录
                CompletableFuture.runAsync(() -> {
                    PrepayDTO prepayDTO = new PrepayDTO();
                    prepayDTO.setOrderId(orderId);
                    prepayDTO.setOrderNo(orderNo);
                    prepayDTO.setUserId(userId);
                    prepayDTO.setAmount(order.getTotalAmount());
                    prepayDTO.setPaymentMethodId(PaymentMethodEnum.WX_PAY.getCode());
                    prepayDTO.setPrepayPackage(prepayPackage);
                    prepayDTO.setStatus(PaymentStatusEnum.UNPAID.getCode());
                    paymentClient.wxPrepay(prepayDTO);
                });

                // 订单回调检查 30分钟后 订单如果没有完成支付 取消订单
                CompletableFuture.delayedExecutor(1, TimeUnit.MINUTES).execute(() -> {
                    log.info("订单回调检查 -- START");
                    Order delayOrder = getById(orderId);
                    Integer status = delayOrder.getStatus();
                    // 判断系统订单状态是否是未支付。此处订单状态一定要是未支付。
                    if (ObjectUtil.equal(status, OrderStatusEnum.UNPAID.getCode())) {
                        // 查询订单状态
                        Transaction transaction = wxClient.wxJsapiQueryOrderByOutTradeNo(orderNo);
                        Transaction.TradeStateEnum tradeState = transaction.getTradeState();
                        if (ObjectUtil.equal(Transaction.TradeStateEnum.SUCCESS, tradeState)) {
                            log.info("订单支付成功 -- START");
                            orderPaySuccess(transaction.getTransactionId(), delayOrder, userId);
                        } else {
                            log.info("订单支付失败 -- START");
                            cancelOrder(delayOrder);
                        }
                    } else {
                        log.info("订单状态已经变更 --- 订单可能已经支付");
                    }
                    log.info("订单回调检查 -- END");
                });
            }
        } catch (Exception e) {
            throw new BusinessException(e.getMessage());
        } finally {
            locker.unlock(lockKey);
        }
        return vo;
    }

    private void orderPaySuccess(String transactionId, Order delayOrder, long userId) {
        // 支付成功
        // 根据订单的pickUp 判断是否自提
        Long orderId = delayOrder.getId();
        if (ObjectUtil.equal(delayOrder.getPickup(), OrderPickupEnum.DELIVERY.getCode())) {
            Order update = new Order();
            update.setId(orderId);
            update.setStatus(OrderStatusEnum.WAITING_FOR_DELIVERY.getCode());
            updateById(update);
        } else if (ObjectUtil.equal(delayOrder.getPickup(), OrderPickupEnum.PICKUP.getCode())) {
            Order update = new Order();
            update.setId(orderId);
            update.setStatus(OrderStatusEnum.WAITING_FOR_PICKUP.getCode());
            updateById(update);
        }
        // 库存扣减
        stockClient.paymentSuccess(orderId);
        // 支付服务更新记录
        PaymentUpdateDTO updateDTO = new PaymentUpdateDTO();
        updateDTO.setOrderId(orderId);
        updateDTO.setTransactionId(transactionId);
        updateDTO.setStatus(PaymentStatusEnum.PAID.getCode());
        paymentClient.updateByOrderId(updateDTO);
        // 用户行为记录
        UserActivityAddDTO activityDTO = new UserActivityAddDTO();
        activityDTO.setUserId(userId);
        activityDTO.setOperationType(OperationTypeEnum.ORDER_PAY.getCode());
        activityDTO.setOrderAmount(delayOrder.getRealAmount());
        activityDTO.setKeyId(orderId);
        userAuthClient.addUserActivity(activityDTO);
    }

    private void cancelOrder(Order delayOrder) {
        // 订单状态 改为 已取消
        Order update = new Order();
        update.setId(delayOrder.getId());
        update.setStatus(OrderStatusEnum.CANCELED.getCode());
        updateById(update);
        // 库存恢复 （库存解锁，库存释放）
        stockClient.paymentFailure(delayOrder.getId());
        // 退还优惠券
        Long couponId = delayOrder.getCouponId();
        if (ObjectUtil.isNotNull(couponId)) {
            couponUserClient.paymentFailure(delayOrder.getUserId(), couponId);
        }
        // 支付服务更新记录
        PaymentUpdateDTO updateDTO = new PaymentUpdateDTO();
        updateDTO.setOrderId(delayOrder.getId());
        updateDTO.setStatus(PaymentStatusEnum.CANCELLED.getCode());
        paymentClient.updateByOrderId(updateDTO);
        // 关闭订单
        wxClient.wxJsapiCloseOrderByOutTradeNo(delayOrder.getOrderNo());
    }

    @Override
    public OrderVO detailById(Long id) {
        Order order = getById(id);
        Assert.notNull(order, () -> new BusinessException("订单不存在"));
        OrderVO vo = new OrderVO();
        org.springframework.beans.BeanUtils.copyProperties(order, vo);
        return vo;
    }

    @Override
    public Long undeliveredOrderCount() {
        return lambdaQuery().in(Order::getStatus, OrderStatusEnum.undeliveredOrder()).count();
    }

    @Override
    public PageVO<OrderVO> pageOrder(OrderPageQuery query) {
        IPage<Order> page = lambdaQuery()
                .like(StrUtil.isNotBlank(query.getOrderNo()), Order::getOrderNo, query.getOrderNo())
                .like(StrUtil.isNotBlank(query.getUsername()), Order::getUsername, query.getUsername())
                .eq(ObjectUtil.isNotNull(query.getPickup()), Order::getPickup, query.getPickup())
                .eq(ObjectUtil.isNotNull(query.getStatus()), Order::getStatus, query.getStatus())
                .ge(ObjectUtil.isNotNull(query.getStartTime()), Order::getCreateTime, query.getStartTime())
                .le(ObjectUtil.isNotNull(query.getEndTime()), Order::getCreateTime, query.getEndTime())
                .orderByDesc(BaseEntity::getCreateTime)
                .page(setPage(query));
        return PageUtils.convert(page, order -> {
            OrderVO vo = new OrderVO();
            org.springframework.beans.BeanUtils.copyProperties(order, vo);
            return vo;
        });
    }

    @Override
    public FeignOrderDetailVO orderItemById(Long id) {
        FeignOrderDetailVO result = new FeignOrderDetailVO();
        List<OrderItem> orderItemList = orderItemMircoService.listByOrderId(id);
        OrderVO orderVO = detailById(id);
        org.springframework.beans.BeanUtils.copyProperties(orderVO, result);
        List<FeignOrderItemVO> orderItemVO = orderItemList.stream().map(orderItem -> {
            FeignOrderItemVO vo = new FeignOrderItemVO();
            org.springframework.beans.BeanUtils.copyProperties(orderItem, vo);
            return vo;
        }).toList();
        result.setOrderItemList(orderItemVO);
        if (ObjectUtil.equal(orderVO.getPickup(), 0)) {
            // Map<地址ID, (用户/手机号//地址) >
            Map<Long, String> userAddressIdAndInfoMap = userAuthClient.addressInfoByIds(List.of(orderVO.getUserAddressId()));
            result.setAddress(userAddressIdAndInfoMap.getOrDefault(orderVO.getUserAddressId(), ""));
        } else {
            result.setAddress(orderVO.getPickupPointName());
        }
        return result;
    }

    @Override
    public Boolean complete(Long id) {
        // 查询订单状态
        Order order = oneById(id);
        // 订单状态为 已发货、待自提 可以完成
        Assert.isTrue(OrderStatusEnum.canComplete().contains(order.getStatus()), () -> new BusinessException("订单状态异常 - 不可完成"));
        // 将订单状态修改为已完成
        Order update = new Order();
        update.setId(order.getId());
        update.setStatus(OrderStatusEnum.COMPLETED.getCode());
        Assert.isTrue(updateById(update), () -> new BusinessException("订单状态修改失败"));
        CompletableFuture.runAsync(() -> {
            // 修改商品销售数量
            Map<Long, Integer> productIdAndQuantity = orderItemMircoService.itemsByOrderId(id).stream().collect(Collectors.toMap(MiniOrderItemVO::getProductId, MiniOrderItemVO::getQuantity));
            productClient.increaseSalesByMap(productIdAndQuantity);
            productClient.updateSalesTimeByIds(productIdAndQuantity.keySet().stream().toList());
        });
        return true;
    }

    @Override
    @Transactional
    public Boolean cancel(Long id) {
        // 查询订单状态
        Order order = oneById(id);
        // 订单状态为 未支付 才可以取消
        Assert.isTrue(ObjectUtil.equal(order.getStatus(), OrderStatusEnum.UNPAID.getCode()), () -> new BusinessException("订单状态异常 - 不可完成"));
        // 将订单状态修改为已取消
        Order update = new Order();
        update.setId(order.getId());
        update.setStatus(OrderStatusEnum.CANCELED.getCode());
        Assert.isTrue(updateById(update), () -> new BusinessException("订单状态修改失败"));
        // 取消订单逻辑
        cancelOrder(order);
        return true;
    }

    @Override
    public List<FeignUserConsumeRankVO> userConsumeRank(Map<Long, String> userIdAndNickname) {
        // 查询所有订单
        Map<Long, List<Order>> userIdAndOrdersMap = lambdaQuery()
                .in(Order::getUserId, userIdAndNickname.keySet())
                .list()
                .stream()
                .filter(order -> CollUtil.contains(OrderStatusEnum.consumeOrder(), order.getStatus()))
                .collect(Collectors.groupingBy(Order::getUserId, Collectors.toList()));
        List<FeignUserConsumeRankVO> rawResult = new ArrayList<>();
        for (Map.Entry<Long, List<Order>> userIdAndOrders : userIdAndOrdersMap.entrySet()) {
            Long userId = userIdAndOrders.getKey();
            String nickname = userIdAndNickname.getOrDefault(userId, "");
            List<Order> orders = userIdAndOrders.getValue();
            // 订单数量
            int orderQuantity = orders.size();
            // 所有订单金额
            BigDecimal allOrderAmount = orders.stream().map(Order::getRealAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
            // 最近下单时间
            LocalDateTime lastOrderTime = orders.stream().map(Order::getCreateTime).max(LocalDateTime::compareTo).orElse(null);
            rawResult.add(new FeignUserConsumeRankVO(userId, nickname, orderQuantity, allOrderAmount, lastOrderTime));
        }
        return rawResult.stream().sorted(Comparator.comparing(FeignUserConsumeRankVO::getConsumeAmount).reversed()).limit(10).toList();
    }

    @Override
    public Map<Integer, Integer> allStatusCount(Long userId) {
        if (ObjectUtil.isNotNull(userId)) {
            ThreadLocalUtils.set(ID, userId.toString());
        }
        Map<Integer, Integer> result = new HashMap<>();
        Integer unPaidCount = getCountByStatus(MiniOrderQueryStatusEnum.UNPAID.getCode());
        Integer unShippedCount = getCountByStatus(MiniOrderQueryStatusEnum.UNSHIPPED.getCode());
        Integer unReceivedCount = getCountByStatus(MiniOrderQueryStatusEnum.UNRECEIVED.getCode());
        Integer unPickedCount = getCountByStatus(MiniOrderQueryStatusEnum.UNPICKED.getCode());
        Integer unCommentedCount = getCountByStatus(MiniOrderQueryStatusEnum.UNCOMMENTED.getCode());
        Integer refundAfterSaleCount = getCountByStatus(MiniOrderQueryStatusEnum.REFUND_AFTER_SALE.getCode());
        result.put(MiniOrderQueryStatusEnum.UNPAID.getCode(), unPaidCount);
        result.put(MiniOrderQueryStatusEnum.UNSHIPPED.getCode(), unShippedCount);
        result.put(MiniOrderQueryStatusEnum.UNRECEIVED.getCode(), unReceivedCount);
        result.put(MiniOrderQueryStatusEnum.UNPICKED.getCode(), unPickedCount);
        result.put(MiniOrderQueryStatusEnum.UNCOMMENTED.getCode(), unCommentedCount);
        result.put(MiniOrderQueryStatusEnum.REFUND_AFTER_SALE.getCode(), refundAfterSaleCount);
        return result;
    }

    private int getCountByStatus(Integer status) {
        List<Integer> statusList = MiniOrderQueryStatusEnum.statusByQueryStatus(status);
        List<Order> orderList = lambdaQuery()
                .eq(Order::getUserId, ThreadLocalUtils.get(ID))
                .in(Order::getStatus, statusList)
                .list();
        return orderList
                .stream()
                .map(order -> {
                    MiniOrderVO orderVO = new MiniOrderVO();
                    org.springframework.beans.BeanUtils.copyProperties(order, orderVO);
                    // 默认设置不能评价
                    orderVO.setCanComment(0);
                    // 该订单是否为已完成订单？
                    if (ObjectUtil.equal(OrderStatusEnum.COMPLETED.getCode(), order.getStatus())) {
                        // 查询用户是否已经评价过该订单
                        orderVO.setCanComment(afterSalesClient.canComment(order.getId()));
                    }
                    return orderVO;
                })
                .filter(orderVO -> {
                    if (ObjectUtil.equal(status, MiniOrderQueryStatusEnum.UNCOMMENTED.getCode())) {
                        return orderVO.getCanComment() == 1;
                    }
                    return true;
                })
                .toList().size();
    }

    @Override
    public PageVO<MiniOrderVO> miniPage(MiniOrderQueryPage queryPage) {
        Integer status = queryPage.getStatus();
        List<Integer> statusList = MiniOrderQueryStatusEnum.statusByQueryStatus(status);
        if (CollUtil.isEmpty(statusList)) {
            return PageUtils.emptyPage();
        }
        IPage<Order> rawPage = lambdaQuery()
                .eq(Order::getUserId, ThreadLocalUtils.get(ID))
                .in(Order::getStatus, statusList)
                .orderByDesc(BaseEntity::getCreateTime)
                .page(setPage(queryPage));
        return PageUtils.convert(rawPage, order -> {
            MiniOrderVO orderVO = new MiniOrderVO();
            org.springframework.beans.BeanUtils.copyProperties(order, orderVO);
            List<OrderItem> orderItems = orderItemMircoService.listByOrderId(order.getId());
            List<MiniOrderItemVO> miniOrderItems = BeanUtils.toBean(orderItems, MiniOrderItemVO.class);
            // 设置图片
            Map<Long, String> productIdAndImage =
                    productClient.listByIds(miniOrderItems.stream().map(MiniOrderItemVO::getProductId).toList()).stream().collect(Collectors.toMap(FeignProductVO::getId, FeignProductVO::getMainImageUrl));
            for (MiniOrderItemVO miniOrderItem : miniOrderItems) {
                String image = productIdAndImage.getOrDefault(miniOrderItem.getProductId(), "");
                miniOrderItem.setProductImage(image);
            }
            orderVO.setItems(miniOrderItems);
            // 默认设置不能评价
            orderVO.setCanComment(0);
            // 该订单是否为已完成订单？
            if (ObjectUtil.equal(OrderStatusEnum.COMPLETED.getCode(), order.getStatus())) {
                // 查询用户是否已经评价过该订单
                orderVO.setCanComment(afterSalesClient.canComment(order.getId()));
            }
            return orderVO;
        }, orderVO -> {
            if (ObjectUtil.equal(status, MiniOrderQueryStatusEnum.UNCOMMENTED.getCode())) {
                return orderVO.getCanComment() == 1;
            }
            return true;
        });
    }

    @Override
    public List<Long> productIdListByOrderIdList(List<Long> keyIdList) {
        if (CollUtil.isEmpty(keyIdList)) {
            return Collections.emptyList();
        }
        return orderItemMircoService.productIdListByOrderIdList(keyIdList);
    }

    @Override
    public Boolean deliverOrPickup(Long id) {
        // 订单状态  1-已支付 2-待发货 时 可以修改订单状态为 发货 或 自提
        Order order = oneById(id);
        Assert.isTrue(CollUtil.contains(OrderStatusEnum.canDeliverOrPickup(), order.getStatus()), () -> new BusinessException("订单状态异常 - 不可发货或自提"));
        // 修改订单状态为 发货 或 自提
        boolean update = lambdaUpdate()
                .eq(BaseEntity::getId, id)
                .set(ObjectUtil.equal(order.getPickup(), OrderPickupEnum.DELIVERY.getCode()), Order::getStatus, OrderStatusEnum.DELIVERED.getCode())
                .set(ObjectUtil.equal(order.getPickup(), OrderPickupEnum.PICKUP.getCode()), Order::getStatus, OrderStatusEnum.WAITING_FOR_PICKUP.getCode())
                .update();
        Assert.isTrue(update, () -> new BusinessException("订单状态更新失败"));
        return true;
    }

    @Override
    public Boolean createOrderPaySuccess(Long id) {
        long userId = Long.parseLong(ThreadLocalUtils.get(ID));
        Order order = oneById(id);
        // 判断系统订单状态是否是未支付。此处订单状态一定要是未支付。
        Assert.equals(order.getStatus(), OrderStatusEnum.UNPAID.getCode(), () -> new BusinessException("订单状态异常 - 不可修改"));
        // 查询微信订单状态
        Transaction transaction = wxClient.wxJsapiQueryOrderByOutTradeNo(order.getOrderNo());
        Transaction.TradeStateEnum tradeState = transaction.getTradeState();
        if (ObjectUtil.equal(Transaction.TradeStateEnum.SUCCESS, tradeState)) {
            CompletableFuture.runAsync(() -> orderPaySuccess(transaction.getTransactionId(), order, userId));
        } else {
            throw new BusinessException("订单尚未完成支付");
        }
        return true;
    }

    @Override
    public void refundSuccess(Long orderId) {
        Order order = new Order();
        order.setId(orderId);
        order.setStatus(OrderStatusEnum.REFUNDED.getCode());
        Assert.isTrue(updateById(order), () -> new BusinessException("订单状态更新失败"));
    }

    /**
     * 根据订单ID 查询订单
     *
     * @param id 订单ID
     * @return 订单
     */
    private Order oneById(Long id) {
        Order order = lambdaQuery().eq(Order::getId, id).one();
        Assert.notNull(order, () -> new BusinessException("订单不存在"));
        return order;
    }
}
